﻿using RIFF;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace WAV
{
    public class Encoder : CodecBase
    {
        public Encoder(CodecProperties newProperties)
        {
            Properties = newProperties;
        }

        protected Chunk BuildDataChunk()
        {
            Chunk result = new Chunk();

            // duplicate the byte data into a chunk
            result.Tag = DataString;
            result.Data = new byte[Data.Length];
            Array.Copy(Data, result.Data, Data.Length);

            return result;
        }

        protected Chunk BuildFormatChunk()
        {
            MemoryStream buffer = new MemoryStream();
            BinaryWriter writer = new BinaryWriter(buffer);

            // PCM is format 0001
            writer.Write((Int16)1);

            // write properties for the sample
            writer.Write((Int16)Properties.Channels);
            writer.Write((Int32)Properties.SampleRate);
            writer.Write((Int32)(Properties.SampleRate * Properties.Channels * Properties.BitsPerSample / 8));
            writer.Write((Int16)(Properties.Channels * Properties.BitsPerSample / 8));
            writer.Write((Int16)Properties.BitsPerSample);
            writer.Flush();

            // put them in a RIFF chunk
            Chunk result = new Chunk();
            result.Tag = FormatString;
            result.Data = buffer.ToArray();

            // clean up
            writer.Close();
            buffer.Dispose();

            return result;
        }

		protected Chunk BuildLoopChunk()
		{
			MemoryStream buffer = new MemoryStream();
			BinaryWriter writer = new BinaryWriter(buffer);

			writer.Write((Int32)0);
			writer.Write((Int32)0);
			writer.Write((Int32)(1000000000 / Properties.SampleRate));
			writer.Write((Int32)0);
			writer.Write((Int32)0);
			writer.Write((Int32)0);
			writer.Write((Int32)0);
			writer.Write((Int32)1);
			writer.Write((Int32)0);
			writer.Write((Int32)0);
			writer.Write((Int32)0);
			writer.Write((Int32)Properties.LoopStart);
			writer.Write((Int32)Properties.LoopStart + Properties.LoopLength);
			writer.Write((Int32)0);
			writer.Write((Int32)0);

			// put them in a RIFF chunk
			Chunk result = new Chunk();
			result.Tag = SmplString;
			result.Data = buffer.ToArray();

			// clean up
			writer.Close();
			buffer.Dispose();

			return result;
		}

        // write RIFF WAV to stream
        public void Encode(Stream target)
        {
            Chunk dataChunk;
            Chunk formatChunk;
			Chunk loopChunk;
            Container result = new Container();

            // build format chunk
            formatChunk = BuildFormatChunk();

            // build data chunk
            dataChunk = BuildDataChunk();

			// build loop chunk
			loopChunk = BuildLoopChunk();
            
            // build RIFF container
            result.FormatTag = WaveString;
            result.Chunks.Add(formatChunk);
            result.Chunks.Add(dataChunk);
			if (Properties.LoopEnabled)
				result.Chunks.Add(loopChunk);

            // write it all to the stream
            result.Write(target);
        }
    }
}
